package com.common.www.controller.auth;

import com.alibaba.fastjson.JSON;
import com.common.www.aop.resolver.CurrentUser;
import org.springframework.boot.base.jpa.domain.PageableRequest;
import com.common.www.bean.entity.Result;
import com.common.www.bean.entity.Sort;
import com.common.www.bean.entity.auth.AuthRole;
import com.common.www.bean.entity.auth.AuthUser;
import com.common.www.bean.entity.auth.Token;
import com.common.www.bean.entity.file.FileCommon;
import com.common.www.bean.vo.UserVo;
import com.common.www.data.NetCode;
import com.common.www.redis.lock.LockName;
import com.common.www.redis.lock.LockUtil;
import com.common.www.service.auth.AccessService;
import com.common.www.service.auth.RoleService;
import com.common.www.service.auth.TokenService;
import com.common.www.service.auth.UserService;
import com.common.www.service.file.FileService;
import com.common.www.service.redis.RedisTemplateService;
import com.common.www.utils.*;
import com.common.www.utils.wechat.WXConstant;
import com.common.www.utils.wechat.WXLoginResponse;
import com.common.www.utils.wechat.WeChatPayUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.common.www.data.NetCode.CODE_TOKEN_INAVALILABLE;

@RestController
@CrossOrigin()
@Api(tags = "API 用户相关接口")
@RequestMapping(value = {"/api/auth/user/"})
public class UserController {
    private static final Logger LOG = LoggerFactory.getLogger(UserService.class);

    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private AccessService accessService;
    @Autowired
    private FileService fileService;
    @Autowired
    TokenService tokenService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    RedisTemplateService redisTemplateService;
    @Autowired
    @Qualifier("simpleRestTemplate")
    protected RestTemplate restTemplate;

    @ApiOperation("登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "唯一凭证可以是手机号、用户名、第三方openId都可以登录"),
            @ApiImplicitParam(name = "password", value = ""),
    })
    // 拦截器直接放行，返回Token
    @RequestMapping(value = "/login", method = {RequestMethod.POST})
    public Result login(String username, String password, HttpServletRequest request, HttpServletResponse response) {
        if (ParamsUtils.isInputEmpty(username)) {
            return R.returnCode(NetCode.CODE_INPUT_OMIT);
        }
        String key = "walletAccount" + username;
        Integer count = redisTemplateService.get(key, Integer.class);//得到重试次数
        if (count != null && count >= 5) {//重试超过5次了
            return R.fail("今日重试次数过多，等一个小时再来试试吧");
        }

        if (count == null) {
            count = 0;
        }

        boolean openIdLogin = false;
        AuthUser authUser = userService.findByUsername(username);

        if (authUser == null && FormatUtils.isMobile(username)) {//未查找到就查找手机号
            authUser = userService.findByPhoneNumber(username);
        }
        if (authUser == null) {
            return R.fail("用户不存在");
        }
        if (authUser.getLocked()) {
            return R.returnCode(NetCode.CODE_AUTH_USER_LOCK);
        }
        if (openIdLogin || passwordEncoder.matches(password, authUser.getPassword())) {//匹配密码,第三方平台登录不验证密码
//        if (password.equals(authUser.getPassword())) {
            UserVo userVo = userService.userToVo(authUser);
            userService.addUserToSession(userVo);
            return R.ok(userVo);
        } else {
            count++;
            redisTemplateService.set(key, count, 1, TimeUnit.HOURS);
            return R.fail((5 - count) == 0 ? "密码错误，等一个小时再来试试吧" : ("密码错误你还有" + (5 - count) + "次机会"));
        }
    }


    @ApiOperation("修改用户信息，主要是为第三方登陆后修改用户信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "String"),
            @ApiImplicitParam(name = "nickName", value = "String"),
            @ApiImplicitParam(name = "gender", value = "1.男 2.女"),
            @ApiImplicitParam(name = "avatarUrl", value = "String"),
    })
    @RequestMapping(value = "/updateByUserId", method = RequestMethod.POST)
    public Result updateByUserId(String userId, String nickName, Integer gender, String avatarUrl) {
        if (ParamsUtils.isInputEmpty(userId)) {
            return ResultUtil.returnFail("参数错误");
        }

        AuthUser authUser = userService.getById(userId);
        if (authUser == null) {
            return ResultUtil.returnFail("用户不存在");
        }
        authUser.setNickName(nickName);
        authUser.setGender(gender);
        String keyName = new IdBitWorker().nextId() + ".jpg";

        FileCommon fileCommon = fileService.saveNetFile(avatarUrl, "jpg", "head", true, true);
        authUser.setAvatar(fileCommon.getAbsPath());

        authUser = userService.save(authUser);
        UserVo userVO = userService.userToVo(authUser);
        Token token = tokenService.findTokenByUser(userVO.getId());
        if (token != null) {
            userVO.setToken(token.getToken());
        }

        return ResultUtil.returnSuccess(userVO);
    }

    @ApiOperation("查询用户根据id")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "String"),
    })
    @RequestMapping(value = "/getById", method = RequestMethod.POST)
    public Result getById(String id) {
        if (ParamsUtils.isInputEmpty(id)) {
            return R.fail("参数缺失");
        }
        AuthUser authUser = userService.getById(id);
        return R.ok(userService.userToVo(authUser));
    }

    @ApiOperation("查询用户根据token")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "token", value = "String"),
    })
    @RequestMapping(value = "/getByToken", method = RequestMethod.POST)
    public Result getByToken(String token) {
        if (ParamsUtils.isInputEmpty(token)) {
            return R.fail("参数缺失");
        }

        UserVo userVo = userService.getUserVoFromRedis(token);
        return R.ok(userVo);
    }


    @ApiOperation("刷新token,根据上一个历史token来获取新的token和使用时间")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "lastToken", value = "微信的临时code码"),
    })
    @RequestMapping(value = "/refreshUserToken", method = RequestMethod.POST)
    public Result refreshUserToken(String lastToken) {
        if (ParamsUtils.isInputEmpty(lastToken)) {
            return R.returnCode(NetCode.CODE_INPUT_OMIT);
        }
        AuthUser authUser = tokenService.findUserByToken(lastToken);
        if (authUser == null) {
            return R.returnCode(CODE_TOKEN_INAVALILABLE);
        }

        UserVo userVo = userService.userToVo(authUser);
        userVo = userService.addUserToSession(userVo);

        return R.ok(userVo);
    }


    @ApiOperation("退出登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "token", value = "String"),
    })
    @RequestMapping(value = "/exitLogin", method = RequestMethod.POST)
    public Result exitLogin(String token) {
//        if (ParamsUtils.isInputEmpty(token)) {
//            return ResultUtil.returnCode(NetCode.CODE_INPUT_OMIT);
//        }
        userService.exitLogin(token);
        return R.ok("退出登录成功");
    }

    @ApiOperation("修改密码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "String"),
            @ApiImplicitParam(name = "oldPassword", value = "需要md5"),
            @ApiImplicitParam(name = "newPassword", value = "需要md5"),
    })
    @RequestMapping(value = "/changePassword", method = RequestMethod.POST)
    public Result changePassword(String userId, String oldPassword, String newPassword) {
        if (ParamsUtils.isInputEmpty(userId, oldPassword, newPassword)) {
            return R.fail("参数缺失");
        }
        AuthUser authUser = userService.getById(userId);
        if (authUser == null) {
            return R.fail("用户不存在");
        }

        if (passwordEncoder.matches(Md5Utils.MD5Encode(oldPassword), authUser.getPassword())) {
            String password = passwordEncoder.encode(Md5Utils.MD5Encode(newPassword));
            authUser.setPassword(password);
            userService.save(authUser);
        } else {
            return R.fail("旧密码不匹配");
        }
        return R.ok(userService.userToVo(authUser));
    }


    @ApiOperation("是否认证通过")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "String"),
    })
    @RequestMapping(value = "/isUserAuth", method = RequestMethod.POST)
    public Result isUserAuth(String userId) {
        if (ParamsUtils.isInputEmpty(userId)) {
            return R.fail("参数缺失");
        }

        AuthUser authUser = userService.getById(userId);
        if (authUser == null) {
            return R.fail("用户信息错误");
        }

        return R.ok(authUser.getStatus());
    }

    @ApiOperation("根据手机号或名称搜索用户(只能生效其中一个)")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "searchName", value = "手机号或名称"),
    })
    @RequestMapping(value = "/searchUserByPhoneOrName", method = RequestMethod.POST)
    public Result searchUserByPhoneOrName(String searchName) {
        if (ParamsUtils.isInputEmpty(searchName)) {
            return R.fail("参数缺失");
        }
        HashMap hashMap = new HashMap();

        if (TxtUtil.isNumeric(searchName)) {
            hashMap.put("phone_like", "%" + searchName + "%");
        } else {
            hashMap.put("name_like", "%" + searchName + "%");
        }
        PageableRequest request = new PageableRequest();
        request.setPage(0);
        request.setSize(10);
        request.setSort(SortUtils.addSort(new Sort("lastUpdateTime", "desc")));
        List<AuthUser> list = userService.getList(hashMap, request);

        List<UserVo> voList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            voList.add(userService.userToVo(list.get(i)));
        }
        return R.ok(voList);
    }

    @ApiOperation("混合搜索医生（名字，医院，科室，描述等）")
    @ApiImplicitParams({
    })
    @RequestMapping(value = "/searchUserByMix", method = RequestMethod.POST)
    public Result searchUserByMix(@CurrentUser UserVo userVo) {
        if (ParamsUtils.isInputEmpty()) {
            return R.fail("参数缺失");
        }
        return R.ok();
    }
    @ApiOperation("得到微信登录的code返回是否需要更新用户信息(小程序使用)")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "微信的临时code码"),
            @ApiImplicitParam(name = "parentId", value = "邀请人id"),
    })
    @RequestMapping(value = "/loginByWxCode", method = RequestMethod.POST)
    public Result loginByWxCode(String code) {
        if (ParamsUtils.isInputEmpty(code)) {
            return ResultUtil.returnCode(NetCode.CODE_INPUT_OMIT);
        }
//        Shop shop = shopService.getById(shopId);
//        if (shop == null) {
//            return ResultUtil.returnFail("小区不存在");
//        }
//        if (!shop.getIsShopConfigAPIFinish()) {
//            return ResultUtil.returnFail("小区未配置完成微信KEY信息,请进入后台配置后再试");
//        }
        String appid = WXConstant.MP_APPID;
        String secret = WXConstant.MP_SECERT;
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
        String res = HttpClient.sendGetRequest(url, null);
        WXLoginResponse response = com.alibaba.fastjson.JSON.parseObject(res, WXLoginResponse.class);

        if (response == null || TxtUtil.isEmpty(response.getOpenid())) {
            return ResultUtil.returnFail("微信登录失败");
        }
        //测试环境暂时不验证openid等缴费了再验证
//        response.setOpenid("fji43jio43j2io432h4b32");
//        response.setOpenid("11111111111111111111111111");
//        if (TxtUtil.isEmpty(response.getOpenid())) {
//            return ResultUtil.returnFail("获取openid失败");
//        }
        //查询用户是否需要
        AuthUser authUser = userService.findByMiniOpenId(response.getOpenid());

        UserVo userVo = null;
        if (authUser == null) {//用户不存在时创建新用户
            authUser = new AuthUser();
            //赋值为普通权限
            AuthRole authRole = roleService.findOne(2L);//普通角色
            if (authRole == null)
                return ResultUtil.returnFail("角色不存在");

            List<AuthRole> roleList = new ArrayList<>();
            roleList.add(authRole);
            authUser.setAuthRoles(roleList);

            authUser.setCreator("三方登录自动创建");
            authUser.setOpenId(response.getOpenid());
            authUser.setUnionid(response.getUnionid());
            authUser.setLocked(false);
            authUser.setFlag(1);
            if (TxtUtil.isEmpty(authUser.getNickName())) {
                authUser.setNickName("普通用户");
            }
            authUser = userService.save(authUser);

        } else {//存在则更新数据
//            String key = LockName.UPDATE_USER.toString() + authUser.getId();
//            //开始抢锁
//            boolean getLock = false;
//            try {
//                getLock = LockUtil.tryLock(key, 10, 5, TimeUnit.SECONDS);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            if (!getLock) {//未抢到
//                return ResultUtil.returnFail("请求失败请稍后重试");
//            }
//
//            if (authUser.getFlag() != 1) {
//                return ResultUtil.returnFail("你的账户已被注销");
//            }
//            if (authUser.getLocked()) {
//                return ResultUtil.returnCode(NetCode.CODE_AUTH_USER_LOCK);
//            }
//
//
//            authUser.setOpenId(response.getOpenid());
//            authUser.setUnionid(response.getUnionid());
//            authUser = userService.save(authUser);
//            LockUtil.unlock(key);
        }

        userVo = userService.userToVo(authUser);
        userVo = userService.addUserToSession(userVo);
//        if (TxtUtil.isEmpty(authUser.getAvatar())) {//用户不存在或昵称为空的时候返回需要更新用户信息
//            userVo.setUpdateUserInfo(true);
//        } else {
            userVo.setUpdateUserInfo(false);
//        }

        return ResultUtil.returnSuccess(userVo);
    }

    @ApiOperation("得到微信登录的code返回是否需要更新用户信息(小程序使用),根据已经登录的token绑定用户手机号")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "微信的临时code码,-1标识模拟登录"),
            @ApiImplicitParam(name = "parentId", value = "邀请人id"),
    })
    @RequestMapping(value = "/loginByWxCodePhone", method = RequestMethod.POST)
    public Result loginByWxCodePhone(String userId, String code) {
        if (ParamsUtils.isInputEmpty(code)) {
            return ResultUtil.returnCode(NetCode.CODE_INPUT_OMIT);
        }

        AuthUser authUser = null;
        String phone = "";
        if (!StringUtils.equals(code, "-1")) {
            String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + weChatPayUtils.getWeChataccessToken();

            // Create a RestTemplate instance
            RestTemplate restTemplate = new RestTemplate();
            // Set the request headers
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            // Set the request body
            String requestBody = "{\"code\":\"" + code + "\"}";
            // Create the request entity
            HttpEntity<String> requestEntity = new HttpEntity<>(requestBody, headers);

            // Make the POST request and get the response entity
            ResponseEntity<String> responseEntity = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    requestEntity,
                    String.class);

            // Get the response body
            String responseBody = responseEntity.getBody();

            WXLoginResponse response = JSON.parseObject(responseBody, WXLoginResponse.class);

//            if (response == null || response.getPhone_info() == null || TxtUtil.isEmpty(response.getPhone_info().getPurePhoneNumber())) {
//                return ResultUtil.returnFail("微信登录失败");
//            }
            //测试环境暂时不验证openid等缴费了再验证
//        response.setOpenid("fji43jio43j2io432h4b32");
//        response.setOpenid("11111111111111111111111111");
//        if (TxtUtil.isEmpty(response.getOpenid())) {
//            return ResultUtil.returnFail("获取openid失败");
//        }
            //查询用户是否需要
            authUser = userService.getById(userId);
            phone = response.getPhone_info().getPurePhoneNumber();
        } else {
            authUser = userService.getById("2");
            phone = authUser.getPhone();
        }


        UserVo userVo = null;
        if (authUser == null) {//用户不存在时创建新用户
            return R.fail("用户登录失败");
        } else {//存在则更新数据
            String key = LockName.UPDATE_USER.toString() + authUser.getId();
            //开始抢锁
            boolean getLock = false;
            try {
                getLock = LockUtil.tryLock(key, 10, 5, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (!getLock) {//未抢到
                return ResultUtil.returnFail("请求失败请稍后重试");
            }

            if (authUser.getFlag() != 1) {
                return ResultUtil.returnFail("你的账户已被注销");
            }
            if (authUser.getLocked()) {
                return ResultUtil.returnCode(NetCode.CODE_AUTH_USER_LOCK);
            }


            authUser.setPhone(phone);
            authUser = userService.save(authUser);
            LockUtil.unlock(key);
        }

        userVo = userService.userToVo(authUser);
        userVo = userService.addUserToSession(userVo);
//        if (TxtUtil.isEmpty(authUser.getAvatar())) {//用户不存在或昵称为空的时候返回需要更新用户信息
//            userVo.setUpdateUserInfo(true);
//        } else {
        userVo.setUpdateUserInfo(false);
//        }

        return ResultUtil.returnSuccess(userVo);
    }

    @Autowired
    WeChatPayUtils weChatPayUtils;

}
